package cn.demoncat.util.ip;

import cn.demoncat.util.exception.IoRuntimeException;
import cn.demoncat.util.ip.config.IpRegionProperties;
import cn.demoncat.util.lang.StringUtil;
import cn.demoncat.util.lang.constant.StatusConstant;
import cn.demoncat.util.web.IpUtil;
import cn.demoncat.util.web.constant.IpConstant;
import cn.demoncat.util.web.entity.IpRegion;
import org.apache.commons.lang3.StringUtils;
import org.lionsoul.ip2region.xdb.Searcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * IP-地址映射
 * 
 * @author 延晓磊
 *
 * @since 2020年5月7日
 */
@Component
public class IpRegionUtil {

	@Resource
	private IpRegionProperties ipRegionProperties;
	
	private Searcher searcher;
	
	private static final Logger LOG = LoggerFactory.getLogger(IpRegionUtil.class);
	
	/**
	 * 查询IP地址映射
	 * 
	 * @param ip
	 * 
	 * @return IP映射（未知IP和内网IP为常量，所以不能编辑）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年5月7日
	 */
	public IpRegion search(String ip) {
		return search(getSearcher(), ip);
	}
	 
	/**
	 * 获取查询器（懒加载）
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年5月11日
	 */
	private Searcher getSearcher() {
		if (searcher == null) {	
			synchronized (this) {
				// 初始化ip2region
				searcher = getSearcher(ipRegionProperties.getDb());
			}
		}
		return searcher;
	}

	/**
	 * 创建Searcher
	 *
	 * @param db
	 * @return
	 */
	private static Searcher getSearcher(String db){
		try {
			// 载入内存，创建Searcher
			return Searcher.newWithBuffer(Searcher.loadContentFromFile(db));
		} catch (Exception e) {
			throw new IoRuntimeException("初始化ip2region.db失败", e);
		}
	}
	
	/**
	 * 查询IP地址映射
	 * 
	 * @param searcher
	 * @param ip
	 * 
	 * @return IP映射（未知IP和内网IP为常量，所以不能编辑）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年5月7日
	 */
	private static IpRegion search(Searcher searcher, String ip) {
		// 错参
		if (StringUtils.isBlank(ip) || !IpUtil.isIp(ip)) {
			return IpRegion.UNKNOWN;
		}
		// 内网
		if (IpUtil.isLocalIp(ip) || IpUtil.isIntranetIp(ip)) {
			return IpRegion.INTRANET;
		}
		// 外网
		String[] result;
		try {
			result = StringUtils.split(searcher.search(ip), '|');
		} catch (Exception e) {
			LOG.warn("通过ip2region查询IP映射地址失败：ip = {}", ip, e);
			return IpRegion.UNKNOWN;
		}
		if (StatusConstant.Common.isNo(result[0])) {
			// 未知
			return IpRegion.UNKNOWN;
		}else if (IpConstant.COUNTRY_TEXT_CN.equals(result[0])) {
			// 国内
			if (StatusConstant.Common.isNo(result[2])) {
				// 未知省
				result[2] = null;
			}
			if (StatusConstant.Common.isNo(result[3])) {
				// 未知市
				result[3] = null;
			}
			if (result[2] != null && result[3] != null && result[3].startsWith(result[2])) {
				// 直辖市
				result[2] = result[3];
				result[3] = null;
			}
			return IpRegion.buildInland(result[2], result[3]);
		}else {
			// 国外
			return IpRegion.buildForeign(result[0], StringUtil.eqToNull(result[2], StatusConstant.Common.NO), StringUtil.eqToNull(result[3], StatusConstant.Common.NO));
		}
	}

}
